package com.wgo.bpot.wiring.db4o;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

import com.wgo.bpot.common.transport.exception.RematoException;
import com.wgo.bpot.common.transport.util.Assert;
import com.wgo.bpot.domain.common.impl.BpotPersistableImpl;
import com.wgo.bpot.wiring.common.DomainModelConventionImpl;

/**
 * @author PEide3
 */
public abstract class Db4oDomainModelConvention<S> extends DomainModelConventionImpl<S> {

	private String setIdentifierMethodName = null ;
	private static Method bpotSetIdentifierMethod ;

	static {
		try {
			bpotSetIdentifierMethod = BpotPersistableImpl.class.getMethod("setIdentifier", Long.class);
		} catch (Exception e) {
			throw new RematoException ("Could not find method for setting identifier for persistable bpot-objects.", e) ;
		}
	}

	
	public Db4oDomainModelConvention() {
		this("setDbId");
	}


	public Db4oDomainModelConvention(String setIdentifierMethodName) {
		super();
		this.setIdentifierMethodName = setIdentifierMethodName;
	}
	


	public String getSetIdentifierMethodName () {
		return setIdentifierMethodName ;
	}

	private Map<Class,Method> conceptToSetIdentifierMethod = new HashMap<Class,Method> () ;
	
	public Method getSetIdentifierMethod (Object concept) {
		Assert.assertNotNull(concept, "Instance to find method to set indentifier from cannot be 'null'.");
		Class conceptClass = concept.getClass() ;
		Method setIdentifierMethod = conceptToSetIdentifierMethod.get(conceptClass);
		if ( null == setIdentifierMethod ) { 
			if (getDomainModelInterface().isInstance(concept)) {
				try {
					setIdentifierMethod = conceptClass.getMethod(getSetIdentifierMethodName(), Long.class ) ;
					conceptToSetIdentifierMethod.put(conceptClass, setIdentifierMethod);
				} catch (Exception e) {
					throw new RematoException ( "Could not find method for setting identifier on domain concept" , e );
				}
				
			} else if (BpotPersistableImpl.class.isInstance(concept)) {
				setIdentifierMethod = bpotSetIdentifierMethod;
			} else {
				throw new RematoException ("Unknown type: " + conceptClass.getSimpleName() + " Cannot find method for setting identifier. Should be assignable from " + getDomainModelInterface().getSimpleName() ) ;
			}
		}
		return setIdentifierMethod ;
	}

}
